home *** CD-ROM | disk | FTP | other *** search
/ Delphi 2.0 - Programmer's Utilities Power Pack / Delphi 2.0 Programmer's Utilities Power Pack.iso / a_to_d / ansmach / ansmach1.pas < prev    next >
Encoding:
Pascal/Delphi Source File  |  1996-09-15  |  15.3 KB  |  514 lines

  1. unit Ansmach1;
  2.  
  3. {=============================================================================}
  4. interface
  5.  
  6. {=============================================================================}
  7. uses
  8.   SysUtils, WinTypes, WinProcs, Messages, Classes, Graphics, Controls,
  9.   Forms, Dialogs, StdCtrls, ExtCtrls, Menus, DLGTIF, AnsMach2;
  10.  
  11. {=============================================================================}
  12. const
  13.   DLG_EVENT = WM_USER + 1;         { unique message for line events }
  14.  
  15.   MSG_GREETING   = 'ansmach0.vox';  { greeting file }
  16.   MSG_MESSAGES   = 'ansmach1.vox';  { callers recorded messages }
  17.   MSG_OPTIONMENU = 'ansmach2.vox';  { remote access option menu }
  18.   MSG_FORWARDING = 'ansmach3.vox';  { call forwarding alert prompt }
  19.  
  20.   PIN = '123#';                     { remote access password }
  21.  
  22.   DETECTLOOP = 0;                   { loop-drop detection }
  23.  
  24. {=============================================================================}
  25. type
  26.   lineState = ( sIdle,            { waiting fo call }
  27.                 sAnswer,          { going off-hook (answer) }
  28.                 sPlayGreeting,    { playing greeting message }
  29.                 sRecordMessage,   { recording callers message }
  30.                 sGetPIN,          { getting remote access PIN }
  31.                 sOptionMenu,      { playing remote access option menu }
  32.                 sGetOption,       { getting option menu choice }
  33.                 sPlayMessages,    { playback recorded messages }
  34.                 sRecordGreeting,  { re-record greeting }
  35.                 sGetForwarding,   { getting new forwarding phone number }
  36.                 sGetMaxMsgCount,  { getting }
  37.                 sCallForwarding,  { calling forwarding number }
  38.                 sPlayForwarding,  { playing forward message alert }
  39.                 sHangUp,          { going on-hook (hanging up) }
  40.                 sSettleLine       { settling line (2 second delay) }
  41.               );
  42.  
  43. {=============================================================================}
  44. type
  45.   TForm1 = class(TForm)
  46.     ListBox1: TListBox;
  47.     Label1: TLabel;
  48.     Label2: TLabel;
  49.     txtForward: TEdit;
  50.     txtMaxMsg: TEdit;
  51.     Label3: TLabel;
  52.     txtMsgCount: TEdit;
  53.     MainMenu1: TMainMenu;
  54.     File1: TMenuItem;
  55.     mnAbout: TMenuItem;
  56.     N2: TMenuItem;
  57.     Exit1: TMenuItem;
  58.  
  59.     procedure FormCreate(Sender: TObject);
  60.     procedure FormDestroy(Sender: TObject);
  61.     procedure mnAboutClick(Sender: TObject);
  62.     procedure Exit1Click(Sender: TObject);
  63.     procedure FormShow(Sender: TObject);
  64.  
  65.   private
  66.     { Private declarations }
  67.  
  68.   public
  69.     { Public declarations }
  70.  
  71.   protected
  72.     lineNo,                    { active channel }
  73.     hFile: word;               { global file handle }
  74.  
  75.     msgForwarded: boolean;     { messages forwarded flag }
  76.  
  77.     currentState: lineState;   { current state of line }
  78.  
  79.     tmpBuf: pchar;             { tmp string buf }
  80.  
  81.     procedure msgProc( var msg: TMessage ); message DLG_EVENT;
  82.     procedure processEvent( lineNo: word );
  83.     procedure changeState( lineNo: word; newState: lineState );
  84.     procedure trace( s: string );
  85.   end;
  86.  
  87. {=============================================================================}
  88. var
  89.   Form1: TForm1;
  90.  
  91.   errNo,                     { global return error }
  92.   hMem: word;                { memory handle }
  93.  
  94.   digitBuf: pChar;           { global DTMF digit buffer }
  95.  
  96.   realPtr: longint;          { pointer to real memory address }
  97.  
  98. {=============================================================================}
  99. implementation
  100.  
  101. {$R *.DFM}
  102.  
  103. {==============================================================================}
  104. function atoi( chr: char ): integer;
  105. begin
  106.   case chr of
  107.     '0'..'9':
  108.       atoi := ord( chr ) - ord( '0' );
  109.  
  110.     else
  111.       atoi := 0;
  112.   end;
  113. end;
  114.  
  115. {==============================================================================}
  116. procedure ReplaceChar( s: pchar; oldChar: char; newChar: char );
  117. var
  118.   p: pchar;
  119.  
  120. begin
  121.   p := StrScan( s, oldChar );
  122.  
  123.   if ( p <> nil ) then
  124.     p^ := newChar;
  125. end;
  126.  
  127. {==============================================================================}
  128. procedure resetFile( fileName: pchar );
  129. begin
  130.   DskFilCls( DskFilCre( fileName, OF_WRITE, errNo ), errNo );
  131. end;
  132.  
  133. {==============================================================================}
  134. function playFile( lineNo: word; voxFile: pchar; var hFile: word ): word;
  135. var
  136.   rwblk: RWB;
  137.  
  138. begin
  139.   clrdtmf( lineNo );  { clear the DTMF buffer for the line }
  140.   clrrwb( rwblk );    { reset RWB to assure defaults }
  141.  
  142.   hFile := DskFilOpn( voxFile, OF_READ, errNo );  { open file }
  143.  
  144.   rwblk.filehndl := hFile;       { handle of file to play from }
  145.   rwblk.loopsig  := detectLoop;  { terminate if drop in loop-current }
  146.   rwblk.termdtmf := ord('@');    { terminate on any digit }
  147.  
  148.   playFile := xplayf( lineNo, PM_NORM, rwblk );  { begin playing }
  149. end;
  150.  
  151. {==============================================================================}
  152. function recordFile( lineNo: word; voxFile: pchar; var hFile: word; append: boolean ): word;
  153. var
  154.   rwblk: RWB;
  155.  
  156. begin
  157.   clrdtmf( lineNo );  { clear the DTMF buffer for the line }
  158.   clrrwb( rwblk );     { reset RWB to assure defaults }
  159.  
  160.   hFile := DskFilOpn( voxFile, OF_WRITE or OF_CREATE, errNo );  { open file }
  161.  
  162.   rwblk.filehndl := hFile;       { handle of file to record to }
  163.   rwblk.loopsig  := detectLoop;  { terminate if drop in loop-current }
  164.   rwblk.termdtmf := ord('#');    { terminate on '#' digit }
  165.   rwblk.rwbflags := RW_TONE;     { begin recording with tone }
  166.   rwblk.rwbdata1 := 3;           { duration of recording tone }
  167.  
  168.   if ( append ) then             { begin record at EOF?... }
  169.     DskFilPos( rwblk.filehndl, 0, SEEK_END, errNo );  { seek to EOF }
  170.  
  171.   recordFile := recfile( lineNo, rwblk, RM_NORM );  { begin recording }
  172. end;
  173.  
  174. {==============================================================================}
  175. function getDigits( lineNo, maxDigits, maxSec: word; flushDigits: boolean ): word;
  176. var
  177.   rwblk: RWB;
  178.  
  179. begin
  180.   clrrwb( rwblk );  { reset RWB to assure defaults }
  181.  
  182.   if ( flushDigits ) then
  183.     clrdtmf( lineNo );
  184.  
  185.   digitBuf[0] := #0;
  186.  
  187.   rwblk.xferseg  := HiWord( realPtr );  { get segment of digit buffer }
  188.   rwblk.xferoff  := LoWord( realPtr );  { get offset of digit buffer }
  189.   rwblk.loopsig  := detectLoop;         { terminate on drop in loop-current }
  190.   rwblk.termdtmf := ord('#');           { terminate on '#' digit }
  191.   rwblk.maxdtmf  := maxDigits;          { max number of digit(s) to accept }
  192.   rwblk.maxsec   := maxSec;             { max seconds to wait for digit(s) }
  193.  
  194.   getDigits := getdtmfs( lineNo, rwblk );  { get digit(s) }
  195. end;
  196.  
  197. {=============================================================================}
  198. procedure TForm1.FormCreate(Sender: TObject);
  199. var
  200.   lineCount: word;  { total channels }
  201.  
  202. begin
  203.   hFile        := 0;
  204.   msgForwarded := False;
  205.   tmpBuf       := StrAlloc( 128 );
  206.  
  207.   errNo := TIFSupIni( 0, 0, 0 );
  208.  
  209.   if ( errNo > 0 ) then
  210.     ShowMessage( 'D4x driver not loaded!' );
  211.  
  212.   errNo := startsys( 0, 0, 0, lineCount );
  213.  
  214.   if ( errNo = E_SUCC ) then
  215.     trace( 'lineCount=' + IntToStr( lineCount ) )
  216.   else
  217.     ShowMessage( 'Unable to initialize driver.' + IntToStr( errNo ) );
  218.  
  219.   lineNo := TIFLinGet( 1, CALLBACK_WINDOW, MakeLong( Handle, DLG_EVENT ) );
  220.  
  221.   if ( lineNo = 0 ) then
  222.     ShowMessage( 'Unable to allocate line 1' );
  223.  
  224.   digitBuf := MemGetRea( realPtr, hMem, 128 );
  225.  
  226.   setcst( lineNo, C_RING or C_OFFH or C_ONH, 1 );
  227.   resetFile( MSG_MESSAGES );
  228.   changeState( lineNo, sIdle );
  229. end;
  230.  
  231. {=============================================================================}
  232. procedure TForm1.FormDestroy(Sender: TObject);
  233. begin
  234.   StrDispose( tmpBuf );
  235.   MemRelRea( hMem );
  236.  
  237.   errNo := TIFLinRel( lineNo, 0, 0 );
  238.   errNo := StopSys;
  239.   errNo := TIFSuptrm;
  240. end;
  241.  
  242. {=============================================================================}
  243. procedure TForm1.FormShow(Sender: TObject);
  244. begin
  245.   mnAboutClick( Sender );
  246. end;
  247.  
  248. {=============================================================================}
  249. procedure TForm1.mnAboutClick(Sender: TObject);
  250. begin
  251.   AboutBox.ShowModal;
  252. end;
  253.  
  254. {=============================================================================}
  255. procedure TForm1.Exit1Click(Sender: TObject);
  256. begin
  257.   Close;
  258. end;
  259.  
  260. {=============================================================================}
  261. procedure TForm1.msgProc( var msg: TMessage );
  262. var
  263.   evtCode,
  264.   evtData,
  265.   lineNo:  word;
  266.  
  267. begin
  268.   evtCode := msg.WParam;
  269.   evtData := LoWord( msg.LParam );
  270.   lineNo  := HiWord( msg.LParam );
  271.  
  272.   trace( '[' + IntToStr( lineNo ) + '] evtCode=' + IntToStr( evtCode ) + ' (' + intToStr( evtData ) + ')' );
  273.  
  274.   processEvent( lineNo );
  275. end;
  276.  
  277. {==============================================================================}
  278. procedure TForm1.processEvent( lineNo: word );
  279. var
  280.   evtCode,
  281.   evtData: word;
  282.  
  283.   evtBlk: TIFEVTBLK;
  284.  
  285.   nextState: lineState;
  286.  
  287. begin
  288.   nextState := sHangup;  { next default state }
  289.  
  290.   if ( hFile > 0 ) then     { was a file opened?... }
  291.     begin
  292.       DskFilCls( hFile, errNo );  { close file }
  293.  
  294.       hFile := 0;
  295.     end;
  296.  
  297.   evtCode := GetLinEvt( lineNo, evtData, evtBlk );  { get event on line }
  298.  
  299.   case currentState of
  300.     sIdle:  { waiting for call }
  301.       case evtCode of
  302.         T_RING:  { only respond to ringing }
  303.           nextState := sAnswer;
  304.       end;
  305.  
  306.     sAnswer:  { answer line }
  307.       case evtCode of
  308.         T_OFFH:
  309.           nextState := sPlayGreeting;
  310.       end;
  311.  
  312.     sHangUp:  { hang up line }
  313.       nextState := sSettleLine;
  314.  
  315.     sSettleLine:  { settle line between calls }
  316.       if ( msgForwarded = True ) or
  317.          ( StrToInt( txtMaxMsg.Text ) = 0 ) or
  318.          ( txtMsgCount.Text < txtMaxMsg.Text ) then
  319.         nextState := sIdle
  320.       else
  321.         nextState := sCallForwarding;
  322.  
  323.     sPlayGreeting:  { play greeting }
  324.       case evtCode of
  325.         T_EOF:
  326.           nextState := sRecordMessage;
  327.  
  328.         T_TERMDT:
  329.           nextState := sGetPIN;
  330.       end;
  331.  
  332.     sRecordMessage:  { record callers message }
  333.       begin
  334.         msgForwarded     := False;
  335.         txtMsgCount.Text := IntToStr( StrToInt( txtMsgCount.Text ) + 1 );
  336.         nextState        := sHangUp;
  337.       end;
  338.  
  339.     sGetPIN:  { get remote access PIN and verify }
  340.       case evtCode of
  341.         T_TERMDT:
  342.           if ( StrComp( digitBuf, PIN ) = 0 ) then
  343.             begin
  344.               msgForwarded := TRUE;
  345.               nextState    := sOptionMenu;
  346.             end;
  347.       end;
  348.  
  349.     sOptionMenu:  { play remote access menu }
  350.       case evtCode of
  351.         T_EOF, T_TERMDT:
  352.           nextState := sGetOption;
  353.       end;
  354.  
  355.     sGetOption:  { get menu choice }
  356.       case evtCode of
  357.         T_MAXDT:
  358.           case digitBuf[0] of
  359.             '1':  { play messages }
  360.               nextState := sPlayMessages;
  361.  
  362.             '2': { erase messages }
  363.               begin
  364.                 resetFile( MSG_MESSAGES );
  365.  
  366.                 txtMsgCount.Text := '0';
  367.                 nextState        := sOptionMenu;
  368.               end;
  369.  
  370.             '3': { re-record greeting }
  371.               nextState := sRecordGreeting;
  372.  
  373.             '4': { change forwarding number }
  374.               nextState := sGetForwarding;
  375.  
  376.             '5': { change forwarding number }
  377.               nextState := sGetMaxMsgCount;
  378.  
  379.             '*': { end call }
  380.               nextState := sHangUp;
  381.           end;
  382.       end;
  383.  
  384.     sPlayMessages:  { play recorded messages }
  385.       case evtCode of
  386.         T_EOF, T_TERMDT:
  387.           nextState := sOptionMenu;  { continue with remote access menu }
  388.       end;
  389.  
  390.     sRecordGreeting:  { re-record greeting }
  391.       case evtCode of
  392.         T_TERMDT:
  393.           nextState := sOptionMenu;  { continue with remote access menu }
  394.       end;
  395.  
  396.     sGetForwarding:  { change call forwarding number }
  397.       case evtCode of
  398.         T_TERMDT:
  399.           begin
  400.             ReplaceChar( digitBuf, '*', ',' );     { replace '*' with ',' }
  401.             ReplaceChar( digitBuf, '#', #0 );      { replace '#' with #0 }
  402.  
  403.             txtForward.SetTextBuf( digitBuf );     { save new forwarding number }
  404.  
  405.             nextState := sOptionMenu;              {continue with remote access menu }
  406.           end;
  407.       end;
  408.  
  409.     sGetMaxMsgCount:  { change max message count }
  410.       case evtCode of
  411.         T_MAXDT:
  412.           begin
  413.             txtMaxMsg.SetTextBuf( digitBuf );    { save new max message count }
  414.  
  415.             nextState := sOptionMenu;            { continue with remote access menu }
  416.           end;
  417.       end;
  418.  
  419.     sCallForwarding:  { call forwarding number }
  420.       { continue with alert message if forwarding number was answered }
  421.       case evtCode of
  422.         T_CATERM:
  423.           if ( evtData = CA_CONN ) then
  424.             nextState := sPlayForwarding;
  425.       end;
  426.  
  427.     sPlayForwarding:  { play forwarding alert message }
  428.       { after alert message, get remote access PIN }
  429.       case evtCode of
  430.         T_EOF, T_TERMDT:
  431.           nextState := sGetPIN;
  432.       end;
  433.   end;
  434.  
  435.   changeState( lineNo, nextState );
  436. end;
  437.  
  438. {==============================================================================}
  439. procedure TForm1.changeState( lineNo: word; newState: lineState );
  440. var
  441.   buf: string;
  442.  
  443. begin
  444.   case newState of
  445.     sIdle:  { waiting for call }
  446.       errNo := 0;
  447.  
  448.     sAnswer:  { answer phone }
  449.       errNo := sethook( lineNo, H_OFFH );
  450.  
  451.     sHangUp:  { hang up phone }
  452.       errNo := sethook( lineNo, H_ONH );
  453.  
  454.     sSettleLine:  { settle line }
  455.       {  NOTE:
  456.            This state is required to assure that the call is properly terminated.
  457.            The goal is to let the line 'settle' for two seconds.  To do this the
  458.            line is tricked to wait for digits even though the line is ON-hook.
  459.            The line will eventuly time-out because no digits were entered. }
  460.  
  461.       errNo := getDigits( lineNo, 1 , 2, TRUE );
  462.  
  463.     sPlayGreeting:  { play greeting message }
  464.       errNo := playFile( lineNo, MSG_GREETING, hFile );
  465.  
  466.     sRecordMessage:  { record callers messages }
  467.       errNo := recordFile( lineNo, MSG_MESSAGES, hFile, TRUE );
  468.  
  469.     sGetPIN:  { get remote access PIN }
  470.       errNo := getDigits( lineNo, 10, 15, FALSE );
  471.  
  472.     sOptionMenu:  { play remote access options }
  473.       errNo := playFile( lineNo, MSG_OPTIONMENU, hFile );
  474.  
  475.     sGetOption:  { get menu option digit }
  476.       errNo := getDigits( lineNo, 1, 15, FALSE );
  477.  
  478.     sPlayMessages:  { play-back recorded messages }
  479.       errNo := playFile( lineNo, MSG_MESSAGES, hFile );
  480.  
  481.     sRecordGreeting:  { re-record greeting }
  482.       errNo := recordFile( lineNo, MSG_GREETING, hFile, FALSE );
  483.  
  484.     sGetForwarding:  { get net forwarding number }
  485.       errNo := getDigits( lineNo, 15, 15, FALSE );
  486.  
  487.     sGetMaxMsgCount:  { get new max message count }
  488.       errNo := getDigits( lineNo, 1, 15, FALSE );
  489.  
  490.     sCallForwarding:  { call forwarding number }
  491.       begin
  492.         txtForward.GetTextBuf( tmpBuf, 128 );
  493.  
  494.         errNo := callp( lineNo, tmpBuf );
  495.       end;
  496.  
  497.     sPlayForwarding:  { play forwarding alert message }
  498.       errNo := playFile( lineNo, MSG_FORWARDING, hFile );
  499.   end;
  500.  
  501.   if ( errNo = 0 ) then
  502.     currentState := newState
  503.   else
  504.     ShowMessage( 'Dialogic error #' + IntToStr( errNo ) );
  505. end;
  506.  
  507. {=============================================================================}
  508. procedure TForm1.trace( s: string );
  509. begin
  510.   ListBox1.Items.Add( s );
  511. end;
  512.  
  513. end.
  514.